home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MACD 5
/
MACD 5.bin
/
workbench
/
tools
/
czesc_3
/
multiuser
/
src
/
library
/
task.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-06-29
|
18KB
|
801 lines
/************************************************************
* MultiUser - MultiUser Task/File Support System *
* --------------------------------------------------------- *
* Task Management Routines *
* --------------------------------------------------------- *
* © Copyright 1993-1994 Geert Uytterhoeven *
* All Rights Reserved. *
************************************************************/
#include <exec/execbase.h>
#include <exec/alerts.h>
#include <intuition/intuitionbase.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include "Memory.h"
#include "Task.h"
#include "Config.h"
#include "Misc.h"
#include "Locale.h"
#include "LibHeader.h"
#include "Monitor.h"
#include "UserInfo.h"
/*
* Static Routines
*/
static struct muTaskLevel *AllocTaskLevel(struct muExtOwner *owner);
static void FreeTaskLevel(struct muTaskLevel *level);
static struct muTaskNode *AllocTaskNode(struct Task *task, ULONG defprotection);
static void FreeTaskNode(struct muTaskNode *node);
static struct muTaskNode *FindTaskNode(struct Task *task);
static void AddTaskLevel(struct muTaskLevel *level, struct muTaskLevel *dest);
static void RemTaskLevel(struct muTaskLevel *level);
static void MoveTaskLevel(struct muTaskLevel *level, struct muTaskLevel *dest);
static void MoveAll(struct muTaskLevel *source, struct muTaskLevel *dest);
static void AddTaskNode(struct muTaskNode *node, struct muTaskLevel *dest);
static void RemTaskNode(struct muTaskNode *node);
static void MoveTaskNode(struct muTaskNode *node, struct muTaskLevel *dest);
static void CleanUpTaskLevel(struct muTaskLevel *level);
static void __saveds CleanUpBody(void);
/*
* Extended Owner Information Structure for root
*/
struct muExtOwner RootExtOwner = {
muROOT_UID, muROOT_GID, 0
};
/*
* Allocate a Task Level
*/
static struct muTaskLevel *AllocTaskLevel(struct muExtOwner *owner)
{
struct muTaskLevel *level;
ULONG size;
size = sizeof(struct muTaskLevel);
if (owner)
size += owner->NumSecGroups*sizeof(UWORD);
if (level = MAlloc(size)) {
NewList((struct List *)&level->Tasks);
NewList((struct List *)&level->Children);
if (owner)
CopyMem(owner, &level->Owner, size-sizeof(struct muTaskLevel)+sizeof(struct muExtOwner));
}
return(level);
}
/*
* Deallocate a Task Level
*/
static void __inline FreeTaskLevel(struct muTaskLevel *level)
{
Free(level, sizeof(struct muTaskLevel)+level->Owner.NumSecGroups*sizeof(UWORD));
}
/*
* Allocate a Task Node
*
* Make sure you have access to the list (via ObtainSemaphore(Shared))!!
*/
static struct muTaskNode *AllocTaskNode(struct Task *task, ULONG defprotection)
{
struct muTaskNode *node;
if (node = MAlloc(sizeof(struct muTaskNode))) {
node->Task = task;
node->DefProtection = defprotection;
}
return(node);
}
/*
* Deallocate a Task Node
*
* Make sure you have access to the list (via ObtainSemaphore(Shared))!!
*/
static void __inline FreeTaskNode(struct muTaskNode *node)
{
Free(node, sizeof(struct muTaskNode));
}
/*
* Find the Task Node for a given Task
*
* Make sure you have access to the list (via ObtainSemaphore(Shared))!!
*/
static struct muTaskNode *FindTaskNode(struct Task *task)
{
struct MinNode *node;
struct muTaskNode *tnode;
for (node = muBase->TaskOwnerList[(ULONG)task%TASKHASHVALUE].mlh_Head;
(node->mln_Succ &&
((tnode = (struct muTaskNode *)((ULONG)node-
(ULONG)&((struct muTaskNode *)NULL)->ListNode))->Task != task));
node = node->mln_Succ);
return(node->mln_Succ ? tnode : NULL);
}
/*
* Add a Task Level
*
* Make sure you have access to the list (via ObtainSemaphore(Shared))!!
*/
static void AddTaskLevel(struct muTaskLevel *level, struct muTaskLevel *dest)
{
AddHead((struct List *)&dest->Children, (struct Node *)&level->Node);
level->Parent = dest;
}
/*
* Remove a Task Level
*
* Make sure you have access to the list (via ObtainSemaphore(Shared))!!
*/
static void __inline RemTaskLevel(struct muTaskLevel *level)
{
Remove((struct Node *)&level->Node);
}
/*
* Move a Task Level to another Task Level
*/
static void MoveTaskLevel(struct muTaskLevel *level, struct muTaskLevel *dest)
{
Remove((struct Node *)&level->Node);
AddHead((struct List *)&dest->Children, (struct Node *)&level->Node);
level->Parent = dest;
}
/*
* Move all TaskNodes and TaskLevels to another Task Level
*/
static void MoveAll(struct muTaskLevel *source, struct muTaskLevel *dest)
{
struct muTaskNode *node;
struct muTaskLevel *level;
while ((node = (struct muTaskNode *)source->Tasks.mlh_Head) && node->LevelNode.mln_Succ)
MoveTaskNode(node, dest);
while ((level = (struct muTaskLevel *)source->Children.mlh_Head) && level->Node.mln_Succ)
MoveTaskLevel(level, dest);
}
/*
* Add a Task Node to a Task Level
*
* Make sure you have access to the list (via ObtainSemaphore(Shared))!!
*/
static void AddTaskNode(struct muTaskNode *node, struct muTaskLevel *dest)
{
AddHead((struct List *)&dest->Tasks, (struct Node *)&node->LevelNode);
AddHead((struct List *)&muBase->TaskOwnerList[(ULONG)node->Task%TASKHASHVALUE],
(struct Node *)&node->ListNode);
node->Level = dest;
CallMonitors(muTrgB_OwnerChange, muNOBODY_UID, dest->Owner.uid, NULL);
}
/*
* Remove a Task Node from a Task Level
*
* Make sure you have access to the list (via ObtainSemaphore(Shared))!!
*/
static void __inline RemTaskNode(struct muTaskNode *node)
{
Remove((struct Node *)&node->LevelNode);
Remove((struct Node *)&node->ListNode);
CallMonitors(muTrgB_OwnerChange, node->Level->Owner.uid, muNOBODY_UID, NULL);
}
/*
* Move a Task Node to another TaskLevel
*
* Make sure you have access to the list (via ObtainSemaphore(Shared))!!
*/
static void MoveTaskNode(struct muTaskNode *node, struct muTaskLevel *dest)
{
Remove((struct Node *)&node->LevelNode);
AddHead((struct List *)&dest->Tasks, (struct Node *)&node->LevelNode);
node->Level = dest;
CallMonitors(muTrgB_OwnerChange, node->Level->Owner.uid, dest->Owner.uid, NULL);
}
/*
* Clean Up a Task Level
*
* Make sure you have access to the list (via ObtainSemaphore(Shared))!!
*/
static void CleanUpTaskLevel(struct muTaskLevel *level)
{
struct muTaskLevel *parent;
while (level && IsListEmpty((struct List *)&level->Tasks) &&
IsListEmpty((struct List *)&level->Children)) {
if (parent = level->Parent)
RemTaskLevel(level);
FreeTaskLevel(level);
level = parent;
};
}
/*
* Init Task List
*/
void InitTaskList(void)
{
ULONG i;
ObtainSemaphore(&muBase->TaskOwnerSem);
for (i = 0; i < TASKHASHVALUE; i++)
NewList((struct List *)&muBase->TaskOwnerList[i]);
ReleaseSemaphore(&muBase->TaskOwnerSem);
}
/*
* Create an Orphan Task Node
*/
struct muTaskNode *CreateOrphanTask(struct Task *task, ULONG defprotection)
{
struct muTaskLevel *level;
struct muTaskNode *node;
ObtainSemaphore(&muBase->TaskOwnerSem);
if (level = AllocTaskLevel(NULL))
if (node = AllocTaskNode(task, defprotection))
AddTaskNode(node, level);
else
FreeTaskLevel(level);
ReleaseSemaphore(&muBase->TaskOwnerSem);
return(node);
}
/*
* Remove all Task Nodes
*/
void RemAllTaskNodes(void)
{
struct muTaskNode *node;
struct muTaskLevel *level;
ULONG i;
ObtainSemaphore(&muBase->TaskOwnerSem);
for (i = 0; i < TASKHASHVALUE; i++)
while ((node = (struct muTaskNode *)muBase->TaskOwnerList[i].mlh_Head) && node->ListNode.mln_Succ) {
level = node->Level;
RemTaskNode(node);
FreeTaskNode(node);
CleanUpTaskLevel(level);
}
ReleaseSemaphore(&muBase->TaskOwnerSem);
}
/*
* Push a Task to a new Owner
*/
BOOL PushTask(struct Task *task, struct muExtOwner *owner)
{
BOOL res = FALSE;
struct muTaskNode *node;
struct muTaskLevel *child, *parent;
ObtainSemaphore(&muBase->TaskOwnerSem);
if ((node = FindTaskNode(task)) || (node = CreateOrphanTask(task, DEFPROTECTION))) {
parent = node->Level;
if (child = AllocTaskLevel(owner)) {
MoveTaskNode(node, child);
AddTaskLevel(child, parent);
res = TRUE;
}
}
ReleaseSemaphore(&muBase->TaskOwnerSem);
return(res);
}
/*
* Push a Task Level to a new Owner
*/
BOOL PushTaskLevel(struct Task *task, struct muExtOwner *owner)
{
BOOL res = FALSE;
struct muTaskNode *node;
struct muTaskLevel *child, *parent;
ObtainSemaphore(&muBase->TaskOwnerSem);
if ((node = FindTaskNode(task)) || (node = CreateOrphanTask(task, DEFPROTECTION))) {
parent = node->Level;
if (child = AllocTaskLevel(owner)) {
MoveAll(parent, child);
AddTaskLevel(child, parent);
res = TRUE;
}
}
ReleaseSemaphore(&muBase->TaskOwnerSem);
return(res);
}
/*
* Pop a Task to the previous Owner
*/
BOOL PopTask(struct Task *task)
{
BOOL res = FALSE;
struct muTaskNode *node;
struct muTaskLevel *child, *parent;
ObtainSemaphore(&muBase->TaskOwnerSem);
if (node = FindTaskNode(task)) {
child = node->Level;
if (parent = child->Parent) {
MoveTaskNode(node, parent);
CleanUpTaskLevel(child);
if (parent->Parent)
res = TRUE;
}
} else
CreateOrphanTask(task, DEFPROTECTION);
ReleaseSemaphore(&muBase->TaskOwnerSem);
return(res);
}
/*
* Pop a Task to the previous Owner and Detach when the Root of the Tree is reached
*/
BOOL PopTaskDetach(struct Task *task)
{
BOOL res = FALSE;
struct muTaskNode *node;
struct muTaskLevel *child, *parent;
ObtainSemaphore(&muBase->TaskOwnerSem);
if (node = FindTaskNode(task)) {
child = node->Level;
if ((parent = child->Parent) && parent->Parent) {
MoveTaskNode(node, parent);
CleanUpTaskLevel(child);
res = TRUE;
} else if (parent = AllocTaskLevel(NULL)) {
MoveTaskNode(node, parent);
CleanUpTaskLevel(child);
}
} else
CreateOrphanTask(task, DEFPROTECTION);
ReleaseSemaphore(&muBase->TaskOwnerSem);
return(res);
}
/*
* Pop a Task Level to the previous Owner and Detach when the Root of the Tree is reached
*/
BOOL PopTaskLevelDetach(struct Task *task)
{
BOOL res = FALSE;
struct muTaskNode *node;
struct muTaskLevel *child, *parent;
ObtainSemaphore(&muBase->TaskOwnerSem);
if (node = FindTaskNode(task)) {
child = node->Level;
if ((parent = child->Parent) && parent->Parent) {
MoveAll(child, parent);
CleanUpTaskLevel(child);
res = TRUE;
} else if (parent = AllocTaskLevel(NULL)) {
MoveAll(child, parent);
CleanUpTaskLevel(child);
}
} else
CreateOrphanTask(task, DEFPROTECTION);
ReleaseSemaphore(&muBase->TaskOwnerSem);
return(res);
}
/*
* Get the Owner (uid:gid) of a Task
*/
ULONG GetTaskOwner(struct Task *task)
{
ULONG owner = muOWNER_NOBODY;
struct muTaskNode *node;
if (!muBase->SecurityViolation) {
ObtainSemaphoreShared(&muBase->TaskOwnerSem);
if (node = FindTaskNode(task))
owner = muExtOwner2ULONG(&node->Level->Owner);
ReleaseSemaphore(&muBase->TaskOwnerSem);
}
return(owner);
}
/*
* Get the Owner (struct muExtOwner *) of a Task
*/
struct muExtOwner *GetTaskExtOwner(struct Task *task)
{
struct muExtOwner *owner = NULL;
struct muTaskNode *node;
ULONG size;
if (!muBase->SecurityViolation) {
ObtainSemaphoreShared(&muBase->TaskOwnerSem);
if (node = FindTaskNode(task)) {
size = sizeof(struct muExtOwner)+node->Level->Owner.NumSecGroups*sizeof(UWORD);
if (owner = (struct muExtOwner *)MAlloc(size))
CopyMem(&node->Level->Owner, owner, size);
}
ReleaseSemaphore(&muBase->TaskOwnerSem);
}
return(owner);
}
/*
* Get the Default Protection Bits for a Task
*/
ULONG GetTaskDefProtect(struct Task *task)
{
ULONG defprotection = DEFPROTECTION;
struct muTaskNode *node;
ObtainSemaphoreShared(&muBase->TaskOwnerSem);
if (node = FindTaskNode(task))
defprotection = node->DefProtection;
ReleaseSemaphore(&muBase->TaskOwnerSem);
return(defprotection);
}
/*
* Set the Default Protection Bits for a Task
*/
BOOL SetTaskDefProtect(struct Task *task, ULONG defprotection)
{
BOOL result;
struct muTaskNode *node;
ObtainSemaphore(&muBase->TaskOwnerSem);
if (node = FindTaskNode(task)) {
node->DefProtection = defprotection;
result = TRUE;
} else
result = (BOOL)CreateOrphanTask(task, defprotection);
ReleaseSemaphore(&muBase->TaskOwnerSem);
return(result);
}
/*
* Set the Default Protection Bits for a Level
*/
BOOL SetLevelDefProtect(struct Task *task, ULONG defprotection)
{
BOOL result;
struct muTaskLevel *level;
struct muTaskNode *node;
ObtainSemaphore(&muBase->TaskOwnerSem);
if (node = FindTaskNode(task)) {
level = node->Level;
for (node = (struct muTaskNode *)level->Tasks.mlh_Head; node->LevelNode.mln_Succ;
node = (struct muTaskNode *)node->LevelNode.mln_Succ)
node->DefProtection = defprotection;
result = TRUE;
} else
result = (BOOL)CreateOrphanTask(task, defprotection);
ReleaseSemaphore(&muBase->TaskOwnerSem);
return(result);
}
/*
* Replacement for the exec.library AddTask() function
*/
APTR __asm __saveds NEWAddTask(register __a1 struct Task *task, register __a2 APTR initpc,
register __a3 APTR finalpc, register __a6 struct ExecBase *sysbase)
{
struct muTaskNode *node;
struct muTaskLevel *level;
ObtainSemaphore(&muBase->TaskOwnerSem);
if (node = FindTaskNode(sysbase->ThisTask)) {
level = node->Level;
if (node = AllocTaskNode(task, node->DefProtection))
AddTaskNode(node, level);
} else
CreateOrphanTask(task, DEFPROTECTION);
ReleaseSemaphore(&muBase->TaskOwnerSem);
return(muBase->OLDAddTask(task, initpc, finalpc, sysbase));
}
/*
* Replacement for the exec.library RemTask() function
*/
void __asm __saveds NEWRemTask(register __a1 struct Task *task, register __a6 struct ExecBase *sysbase)
{
struct muTaskNode *node;
struct muTaskLevel *level;
if (!task)
task = sysbase->ThisTask;
ObtainSemaphore(&muBase->TaskOwnerSem);
if (node = FindTaskNode(task)) {
level = node->Level;
RemTaskNode(node);
FreeTaskNode(node);
CleanUpTaskLevel(level);
}
ReleaseSemaphore(&muBase->TaskOwnerSem);
muBase->OLDRemTask(task, sysbase);
}
/*
* Get the Owner (uid:gid) of a Task
*
* Public Library Function
*/
ULONG __asm __saveds muGetTaskOwner(register __d0 struct Task *task)
{
if (!task)
task = SysBase->ThisTask;
return(GetTaskOwner(task));
}
/*
* Get the Owner (struct muExtOwner *) of a Task
*
* Public Library Function
*/
struct muExtOwner __asm __saveds *muGetTaskExtOwner(register __d0 struct Task *task)
{
if (!task)
task = SysBase->ThisTask;
return(GetTaskExtOwner(task));
}
/*
* Free an Extended Owner structure
*
* Public Library Function
*/
void __asm __saveds muFreeExtOwner(register __a0 struct muExtOwner *owner)
{
ULONG size;
if (owner) {
size = sizeof(struct muExtOwner)+owner->NumSecGroups*sizeof(UWORD);
Free(owner, size);
}
}
/*
* Kill a task or process
*
* Public Library Function
*
* This function may be called by root only!
*/
BOOL __asm __saveds muKill(register __d0 struct Task *task)
{
BOOL res = FALSE;
UBYTE *sp;
ULONG size;
struct muExtOwner *xowner;
xowner = GetTaskExtOwner(SysBase->ThisTask);
if (task && (task != SysBase->ThisTask) && (task != muBase->Server) &&
(muGetRelationshipA(xowner, NULL, NULL) & muRelF_ROOT_UID)) {
Disable();
switch (task->tc_Node.ln_Type) {
case NT_TASK:
RemTask(task);
res = TRUE;
break;
case NT_PROCESS:
Remove(task);
task->tc_State = TS_READY;
sp = task->tc_SPReg;
if (SysBase->AttnFlags & AFF_68881) {
if (size = *(ULONG *)sp) {
sp += 110;
if (size == 0x90)
sp += 12;
if ((SysBase->LibNode.lib_Version > 37) || ((SysBase->LibNode.lib_Version == 37) &&
(SysBase->LibNode.lib_Revision >= 132)))
sp += 2;
size = sp[1];
sp += size;
}
sp += 4;
}
*(ULONG *)sp = (ULONG)CleanUpBody;
AddHead(&SysBase->TaskReady, task);
res = TRUE;
break;
}
Enable();
}
muFreeExtOwner(xowner);
return(res);
}
/*
* Clean up a dead process
*/
static void __saveds CleanUpBody(void)
{
struct Task *task;
struct Screen *scr, *t;
struct Window *win;
struct MsgPort *port;
struct Requester *req;
BOOL doclose;
task = SysBase->ThisTask;
Forbid();
scr = IntuitionBase->FirstScreen;
while (scr) {
doclose = FALSE;
win = scr->FirstWindow;
while (win)
if ((port = win->UserPort) && (port->mp_SigTask == task)) {
ModifyIDCMP(win, NULL);
ClearDMRequest(win);
ClearMenuStrip(win);
ClearPointer(win);
while (req = win->FirstRequest)
EndRequest(req, win);
CloseWindow(win);
doclose = TRUE;
win = scr->FirstWindow;
} else
win = win->NextWindow;
t = scr->NextScreen;
if (doclose && ((scr->Flags & SCREENTYPE) != WBENCHSCREEN))
CloseScreen(scr);
scr = t;
}
Exit(NULL);
}
/*
* Freeze a task or process
*
* Public Library Function
*
* This function may be called by root only!
*/
BOOL __asm __saveds muFreeze(register __d0 struct Task *task)
{
BOOL res = FALSE;
struct muExtOwner *xowner;
xowner = GetTaskExtOwner(SysBase->ThisTask);
if (task && (task != SysBase->ThisTask) && (task != muBase->Server) &&
(muGetRelationshipA(xowner, NULL, NULL) & muRelF_ROOT_UID)) {
Disable();
switch (task->tc_Node.ln_Type) {
case NT_TASK:
case NT_PROCESS:
if (task->tc_State < 7) {
Remove(task);
AddHead((struct List *)&muBase->Frozen, task);
task->tc_State += 7;
res = TRUE;
}
break;
}
Enable();
}
muFreeExtOwner(xowner);
return(res);
}
/*
* Unfreeze a task or process
*
* Public Library Function
*
* This function may be called by root only!
*/
BOOL __asm __saveds muUnfreeze(register __d0 struct Task *task)
{
BOOL res = FALSE;
struct muExtOwner *xowner;
xowner = GetTaskExtOwner(SysBase->ThisTask);
if (task && (muGetRelationshipA(xowner, NULL, NULL) & muRelF_ROOT_UID)) {
Disable();
switch (task->tc_Node.ln_Type) {
case NT_TASK:
case NT_PROCESS:
if (task->tc_State >= 7) {
Remove(task);
if ((task->tc_State -= 7) == TS_READY)
Enqueue(&SysBase->TaskReady, task);
else
Enqueue(&SysBase->TaskWait, task);
res = TRUE;
}
break;
}
Enable();
}
muFreeExtOwner(xowner);
return(res);
}